I conduct a STM (Strucutral Topic Model) estimation on a sample of 11,919 online news articles from seven news provider about domestic politics: Bild.de, DIE WELT, FOCUS ONLINE, SPIEGEL ONLINE, Stern.de, ZEIT ONLINE, Tagesschau.de. The articles are dated from 01.06.2017 to 31.12.2017 (German federal elections took place on 24th of September 2017.). I first extract all online articles using the the Eventregistry API. Then all articles from the section “domestic policy” are filtered by checking the URL structure.
To discover the latent topics in the corpus, the structural topic modeling (STM) developed by Roberts (2016) is applied. The STM is an unsupervised machine learning approach that models topics as multinomial distributions of words and documents as multinomial distributions of topics, allowing to incorporate external variables that effect both, topical content and topical prevalence. I will included the news provider as a control for both the topical content and the topical prevalence. Additional, the month an article was published is included as a control for the topical prevalence. The number of topics is set to 35.
The Figures below show the distribution of the number of articles from the respective news sources by date. There is a high peak around the federal elections on September, 24th.
ggsave({
btw %>%
ggplot(aes(site)) +
geom_bar(fill=col[1], alpha= .8) +
labs(x="", y="Number of articles") +
theme(
legend.position = "none"
)
},
filename = "../figs/bar.png", device = "png",
width = 6, height = 4,
dpi = 600)plot1
ggsave({
btw %>%
group_by(date) %>%
dplyr::summarise(obs = n()) %>%
ggplot(aes(date, obs)) +
geom_line(color=col[3]) +
geom_vline(aes(xintercept=as.Date("2017-09-24")),
linetype = 2, color=col[2]) +
scale_color_manual(values = col) +
labs(x="", y="number of articles",color="") +
scale_x_date(breaks = date_breaks("1 month"), labels=date_format("%B", tz="CET")) +
theme(
legend.position = "none",
axis.title.x = element_blank(),
axis.text = element_text(size = 8)
)
},
filename = "../figs/timeline.png", device = "png",width = 6, height = 4,
dpi = 600
)plot1
In order to improve readability and traceability, I assign a shorter name to the topics based on the most common words. The plotQuote function allows to inspect die most common words of a topic for each covariate.
topics <- matrix(c(1, "SPD, M.Schulz", 2, "A.Merkel vs. Schulz", 3, "Jamaica coalition", 4, "Diesel scandal", 5, "H.Kohl", 6, "A.Merkel", 7, "Federal Election Results", 8, "Seehover vs. Söder, CSU", 9, "EU policies, refugee policy", 10, "German Parliament, parliamentarians", 11, "Mix: DIE LINKE, W.Schäuble", 12, "Refugees, deportation", 13, "Mix: Schröder, IT Topics", 14, "B90/Die Grünen", 15, "USA, Russia, Israel", 16, "Great coalition", 17, "A.Weidel (AfD)", 18, "Budget statistics, Welfare policy", 19, "Process Error", 20, "Federal Constitutional Court, Ministry of the Interior", 21, "German armed forces, Mali", 22, "Mix: Weather, DB, nuclear transport, ...", 23, "Elections in Niedersachsen", 24, "CDU / CSU", 25, "Mix: political talkshows, Berxit, Macron", 26, "Mix: F.-W.Steinmeier, Constitution, H.Maas", 27, "public statistics", 28, "Election polls", 29, "F.Petry, Gauland (AfD)", 30, "Mix: NSU, sexism", 31, "German armed forces, V.d.Leyen", 32, "G20 in Hamburg", 33, "Turkey, S.Gabriel", 34, "police reports, terror (left-, right-wing, IS)", 35, "Seehofer, refugee cap"), ncol=2, byrow=T)
topics.df <- as.data.frame(topics) %>%
transmute(topic_name = paste(V1, V2, sep=": "),
topic = 1:k) Next, we can assign a topic to each document (topic with highest postertior gamma)
# Document-topic probabilities
stmOut %>% tidy("theta") -> theta
top_topics <- theta %>%
group_by(document) %>%
mutate(therank = rank(-gamma)) %>%
filter(therank == 1) %>%
select(- therank)
btw.2 <- btw %>%
mutate(document = articleID) %>%
merge(.,top_topics, by="document") %>%
## Combine with Topic label
merge(., topics.df, by="topic") %>%
mutate(allocation = 1) btw.2 %>%
ggplot(aes(gamma)) +
geom_density(color = col[3],
fill = col[3], alpha=.7) +
labs(x="Distribution of gamma value")In order to get an initial overview of the results, the figure below displays the topics ordered by their expected frequency across the corpus (left side of the Figure) and the expected proportion of a topic in public media minus the expected proportion of topic use in private media (right side of the Figure). Thus topics more associated with public media appear to the right of zero. To assign a label to each topic, I looked at the most frequent words in that topic and the most representative articles.
keep <- seq(1:k)frequency <- as.data.frame(colMeans(stmOut$theta)) %>%
mutate(frequency = colMeans(stmOut$theta),
topic = topics[,1],
topic_name=paste(topics[,1],topics[,2],
sep=": ")) %>%
filter(topic %in% keep)
freq <- tapply(stmOut$theta[,1], stmOut$settings$covariates$betaindex, mean)
freq <- as.data.frame(freq) %>%
mutate(site=stmOut$settings$covariates$yvarlevels,
topic = 1)
for(i in 2:k) {
freq1 <- tapply(stmOut$theta[,i], stmOut$settings$covariates$betaindex, mean)
freq1 <- as.data.frame(freq1) %>%
transmute(site=stmOut$settings$covariates$yvarlevels,
topic = i,
freq = freq1)
freq <- rbind(freq, freq1)
}
freq <- freq %>%
left_join(., topics.df, by = "topic") %>%
#filter(topic %in% keep) %>%
mutate(topic = topic_name) %>%
left_join(., frequency %>% select(topic, frequency),
by = "topic")p1 <- ggplot(frequency, aes(x=reorder(topic_name, frequency), y=frequency)) +
geom_col(fill=col[1], alpha=0.8) +
coord_flip() +
labs(x="", y="expected frequency") +
theme(axis.text.x = element_text(size=8),
axis.text.y = element_text(size=11),
axis.title = element_text(size=10))
p1p2 <- ggplot(freq, aes(reorder(topic_name,frequency), freq)) +
geom_col(fill = col[3]) +
coord_flip() +
facet_wrap(~site, ncol = 7) +
theme(
#axis.text.y = element_blank(),
axis.text.y = element_text(size=11),
axis.title = element_text(size=10)) +
labs(x="", y="expected frequency")
p2 Keep only those articles, that are clear & interessting to analyse.
keep <- c(1,16,24,29,3,6,8)To identify which of these differences is significant, the conditional expectation of topic prevalence for given document characteristics can be estimated. More specifically, I estimate a linear model, where the documents are observations, the dependent variable is the posterior probability of a topic and the covariates are the metadata of documents (see equation below).
\[ \theta_d=\alpha+\beta_1x_{ownership}+\beta_2x_{month}+\epsilon \]
The estimateEffect() uses the method of composition to incorporate uncertainty in the dependent variable, drawing a set of topic proportions from the variational posterior repeated times and compute the coefficients as the average over all results.
effect <- estimateEffect(c(1:k) ~site+s(month), stmOut,
metadata = out$meta, uncertainty = "None")Here, I create a dataframe that contains the results of the estimation.
tables <- vector(mode="list", length = length(effect$topics))
for (i in seq_along(effect$topics)) {
sims <- lapply(effect$parameters[[i]], function(x) stm:::rmvnorm(500, x$est, x$vcov))
sims <- do.call(rbind, sims)
est <- colMeans(sims)
se <- sqrt(apply(sims,2, stats::var))
tval <- est/se
rdf <- nrow(effect$data) - length(est)
p <- 2*stats::pt(abs(tval), rdf, lower.tail = FALSE)
topic <- i
coefficients <- cbind(topic, est, se, tval, p)
rownames(coefficients) <- attr(effect$parameters[[1]][[1]]$est, "names")
colnames(coefficients) <- c("topic", "Estimate", "Std. Error", "t value", "p")
tables[[i]] <- coefficients
}
out1 <- list(call=effect$call, topics=effect$topics, tables=tables)
coeff <- as.data.frame(do.call(rbind,out1$tables))
coeff <- coeff %>%
mutate(parameter = rownames(coeff),
parameter = gsub("site", "", parameter),
parameter = ifelse(parameter == "s(month)1", "1_July", parameter),
parameter = ifelse(parameter == "s(month)2", "2_August", parameter),
parameter = ifelse(parameter == "s(month)3", "3_September", parameter),
parameter = ifelse(parameter == "s(month)4", "4_October", parameter),
parameter = ifelse(parameter == "s(month)5", "5_November", parameter),
parameter = ifelse(parameter == "s(month)6", "6_December", parameter),
signifcant = ifelse(p <= 0.5,"yes","no")) %>%
left_join(., topics.df, by="topic")The following figure shows the regression results for each news page. The coefficients indicate the deviation from the base value of Bild.de (keeping the month equal).
p1 <- coeff %>%
filter(topic %in% keep) %>%
filter(parameter %in% stmOut$settings$covariates$yvarlevels) %>%
ggplot(aes(x = reorder(topic_name,topic, decreasing=F), y = Estimate, fill=factor(signifcant))) +
geom_col() +
scale_fill_manual(values = col[c(2,1)]) +
scale_x_discrete(position = "top") +
coord_flip() +
facet_wrap(~parameter, ncol = 8, scales = "free_x") +
labs(x="", fill="significant at the 5% level") +
theme(legend.position = "top",
axis.text.y = element_text(size=9),
axis.text.x = element_text(angle=90))
p1# ggsave(plot = p1, filename = "../figs/estimates.png", device = "png",width = 10, height = 7,
# dpi = 600)The following figure shows the regression results for each month. The coefficients indicate the deviation from the base value of June 2017 (keeping the news source).
p1 <- coeff %>%
filter(topic %in% keep) %>%
filter(!parameter %in% stmOut$settings$covariates$yvarlevels) %>%
filter(parameter != "(Intercept)") %>%
ggplot(aes(x = reorder(topic_name,topic, decreasing=F), y = Estimate, fill=factor(signifcant))) +
geom_col() +
scale_fill_manual(values = col[c(2,1)]) +
scale_x_discrete(position = "top") +
coord_flip() +
facet_wrap(~parameter, ncol = 8, scales = "free_x") +
labs(x="", fill="significant at the 5% level") +
theme(legend.position = "top",
axis.text.y = element_text(size=9),
axis.text.x = element_text(angle=90))
p1The idea of Sentiment analysis is to determine the attitude of a writer through online text data toward certain topic or the overall tonality of a document.
Lexical or “bag-ofwords” approaches are commonly used. In that approach, the researcher provides pre-defined dictionaries (lists) of words associated with a given emotion, such as negativity. The target text is then deconstructed into individual words (or tokens) and the frequencies of words contained in a given dictionary are then calculated.
SentimentWortschatz, or SentiWS for short, is a publicly available German-language resource for sentiment analysis, opinion mining etc. It lists positive and negative polarity bearing words weighted within the interval of [-1; 1] plus their part of speech tag, and if applicable, their inflections. The current version of SentiWS (v1.8b) contains 1,650 positive and 1,818 negative words, which sum up to 15,649 positive and 15,632 negative word forms incl. their inflections, respectively. It not only contains adjectives and adverbs explicitly expressing a sentiment, but also nouns and verbs implicitly containing one.
sent <- c(
# positive Wörter
readLines("dict/SentiWS_v1.8c_Negative.txt",
encoding = "UTF-8"),
# negative Wörter
readLines("dict/SentiWS_v1.8c_Positive.txt",
encoding = "UTF-8")
) %>% lapply(function(x) {
# Extrahieren der einzelnen Spalten
res <- strsplit(x, "\t", fixed = TRUE)[[1]]
return(data.frame(words = res[1], value = res[2],
stringsAsFactors = FALSE))
}) %>%
bind_rows %>%
mutate(word = gsub("\\|.*", "", words) %>% tolower,
value = as.numeric(value)) %>%
# manche Wörter kommen doppelt vor, hier nehmen wir den mittleren Wert
group_by(word) %>% summarise(value = mean(value)) %>% ungroupWe now take each word in each article and assign a sentiment value for that word. I only use articles that have been assigned a topic with a probability of over 90% (gamma > 0.9).
calculate sentiment value of document \(d\):
\[ \text{Sentiment}_d = \frac{|\text{Sum of positive tokens}_d| - |\text{Sum of negative tokens}_d|}{\text{Number ot tokens}_d} \]
sentDF.values <- sentDF %>%
select(document, word, value, polarity) %>%
mutate(id = row_number()) %>%
spread(polarity, value) %>%
group_by(document) %>%
# calculate sum of positive and negative values
summarise(sum_positive = sum(positive, na.rm = T),
sum_negative = sum(negative, na.rm = T)) %>%
# calculate diff
mutate(sent_diff = abs(sum_positive) - abs(sum_negative)) %>%
# combine with dataframe
left_join(., df,
by = "document") %>%
# calculate sentiment
mutate(sentiment = sent_diff / text_length)p <- sentDF.values %>%
group_by(topic_name) %>%
summarise(sentiment = mean(sentiment, na.rm=T),
obs = n())
ggplot(p, aes(reorder(topic_name, sentiment),
sentiment,
label = obs)) +
geom_col(fill = col[1], alpha = 0.7) +
geom_text() +
geom_hline(yintercept = 0, linetype = 2,
color = "black") +
coord_flip() +
labs(x="", y="",
title = "Grouped Sentiment value",
fill = "Number of\nObservations") +
theme(axis.text.y = element_text(size = 10))p <- sentDF.values %>%
group_by(site) %>%
summarise(sentiment = mean(sentiment, na.rm=T),
obs = n())
ggplot(p, aes(reorder(site, sentiment),
sentiment,
label = obs)) +
geom_col(fill = col[3], alpha = 0.7) +
geom_text() +
geom_hline(yintercept = 0, linetype = 2,
color = "black") +
coord_flip() +
labs(x="", y="",
title = "Grouped Sentiment value",
fill = "Number of\nObservations") +
theme(axis.text.y = element_text(size = 10))p <- sentDF.values %>%
group_by(site, topic_name, topic) %>%
summarise(sentiment = mean(sentiment, na.rm=T),
obs = n())
ggplot(p,
aes(reorder(topic_name, topic),
sentiment, label = obs)) +
geom_col(fill=col[1], alpha = 0.7) +
geom_text() +
geom_hline(yintercept = 0, linetype = 2,
color = "black") +
coord_flip() +
facet_wrap(~site, ncol = 7) +
labs(x="", y="", fill= "Number of\nObservations",
title = "Sentiment value") +
theme(axis.text.y = element_text(size=12))sentDF.values %>%
filter(topic == 6) %>%
select(title, sentiment, site) %>%
htmlTable::htmlTable(align = "l")| title | sentiment | site | |
|---|---|---|---|
| 1 | Heftiger GroKo-Zoff um Glyphosat-Entscheidung - Seehofer soll von Alleingang gewusst haben | -0.000954561101549053 | Bild.de |
| 2 | Nachtschicht der Unionsspitzen: Wo geht's denn hier zurück nach rechts? - WELT | -0.00470754901960784 | DIE WELT |
| 3 | Treffen der Unionsspitzen: CDU und CSU vor Durchbruch bei Zuwanderung - WELT | -0.0053354743083004 | DIE WELT |
| 4 | Vor dem Gipfel zu einer neuen Großen Koalition: Stimmung ist vergiftet | -0.00442064451158107 | Bild.de |
| 5 | Presseschau zur "Ehe für alle": "Komplette Restentkernung der Union" - FOCUS Online | -0.00229613034623218 | FOCUS ONLINE |
| 6 | Ehe für alle: Was bedeutet das Ergebnis der Abstimmung im Bundestag? | -0.00221148648648649 | SPIEGEL ONLINE |
| 7 | Kritik und Applaus für die Kanzlerin - Familien-Krach bei Merkels Nachwuchs | -0.000640507726269315 | Bild.de |
| 8 | Glyphosat-Genehmigung: Schmidts Solo und die Folgen - SPIEGEL ONLINE - Politik | -0.00636744444444444 | SPIEGEL ONLINE |
| 9 | Merkel im ZDF: Rücktritt? "Nein, das stand nicht im Raum" - WELT | -0.00115571913929785 | DIE WELT |
| 10 | Merkel im ZDF: "Ich fürchte gar nichts" - WELT | -0.00115702947845805 | DIE WELT |
| 11 | "Dresdner Erklärung": Junge Union rechnet nach Wahldebakel mit Angela Merkel ab - WELT | 9.99999999999998e-05 | DIE WELT |
| 12 | Merkels Kurswechsel: Kein klares Nein mehr zur "Ehe für alle" | tagesschau.de | -0.000650067294751009 | Tagesschau.de |
| 13 | Nach Glyphosat-Entscheidung: Merkel rügt Minister Schmidt | -0.00433584379358438 | Tagesschau.de |
| 14 | Ausschuss macht Weg frei: Entscheidung zu Ehe für alle am Freitag | -0.0034563025210084 | stern.de |
| 15 | Debatte um Gleichstellung: Abstimmung zu Ehe für alle - Rechtsausschuss macht Weg frei | -0.000796120689655172 | stern.de |
| 16 | Kritischer Nachwuchs, werbende Kanzlerin: Neue Töne auf dem Weg nach Jamaika | 0.000422988505747126 | FOCUS ONLINE |
| 17 | Seehofer sieht Koalitionsbruch: Koalitionskrach über Ehe für alle verschärft sich | -0.000528528528528529 | stern.de |
| 18 | Abstimmung im Bundestag: Historische Entscheidung zur «Ehe für alle» möglich | -0.00314878787878788 | stern.de |
| 19 | CDU und CSU: Die ÖVP loben, Merkel treffen | -0.00479510703363914 | ZEIT ONLINE |
| 20 | Gleichgeschlechtliche Partnerschaften: Wie Merkel den Weg für die Ehe für alle frei machte | -0.00235598755832037 | ZEIT ONLINE |
| 21 | "Ehe für alle" - Merkels Vorstoß war kein Betriebsunfall, sondern Ergebnis langer Überlegungen | -0.004620294599018 | FOCUS ONLINE |
| 22 | Unions-Spitze überrumpelt: Nach Merkels Rückzieher: Votum zur Ehe für alle am Freitag | 0.00210248344370861 | stern.de |
| 23 | Vor Gipfel mit der CDU: Die neue Flexibilität der CSU beim Begriff "Obergrenze" - WELT | -0.00193962900505902 | DIE WELT |
| 24 | CDU, CSU: Mit diesem Zehn-Punkte-Plan geht Seehofer zu Angela Merkel - WELT | -0.00233671742808799 | DIE WELT |
| 25 | Debatte um Gleichstellung: Koalitionskonflikt um Ehe für alle verschärft sich | -0.00178084358523726 | stern.de |
| 26 | Bundestag wird am Freitag über Ehe für alle abstimmen | -0.00215027322404372 | Tagesschau.de |
| 27 | Ehe für alle: SPD drängt auf namentliche Abstimmung - Union kritisiert Merkel - FOCUS Online | -0.00422364990689013 | FOCUS ONLINE |
| 28 | Junge Union: Der Elefant im Raum | -0.000625519848771267 | ZEIT ONLINE |
| 29 | Historische Entscheidung: Bundestag stimmt Ehe für alle zu | -0.00116302681992337 | stern.de |
| 30 | Ehe für alle: Merkel rückt von CDU-Kurs ab - Abstimmung diese Woche gefordert - FOCUS Online | 0.000111740890688259 | FOCUS ONLINE |
| 31 | "Ehe für alle" im Bundestag: SPD will Abstimmung noch diese Woche | tagesschau.de | -4.26804123711341e-05 | Tagesschau.de |
| 32 | Gleichstellung: Merkel rückt vom Nein der CDU zur Ehe für alle ab | 0.00023091286307054 | stern.de |
| 33 | Bundestagswahlkampf: Merkel rückt vom Nein zur Ehe für alle ab | -0.00282320675105485 | SPIEGEL ONLINE |
| 34 | Streit mit SPD - Schmidt verteidigt Glyphosat-Ja | -0.00273404255319149 | Tagesschau.de |
| 35 | Heidelberg: Angela Merkel bei Wahlkampfauftritt mit Tomaten beworfen | -0.00422688172043011 | stern.de |
| 36 | Asylkompromiss in der Union: Seehofer zitiert zufrieden das Ende des zweiten Absatzes - WELT | -0.00133529411764706 | DIE WELT |
| 37 | Glyphosat: SPD wirft CSU-Minister Vertrauensbruch vor | -0.00107538126361656 | ZEIT ONLINE |
| 38 | Gesetzesreform: Historische Entscheidung: Bundestag beschließt "Ehe für alle" | 0.000554203539823009 | stern.de |
| 39 | Vorfall in Heidelberg: Merkel bei Wahlkampfauftritt mit Tomaten beworfen | -0.00494176072234763 | stern.de |
| 40 | Spahn im BaB: "Dieses Land ist bürgerlich wie lange nicht" | 0.00141890660592255 | Tagesschau.de |
| 41 | Zwischenfall in Heidelberg: Merkel bei Wahlkampfauftritt mit Tomaten beworfen | -0.00504348837209302 | stern.de |
| 42 | Streit um "Ehe für alle": Das sind die Rechte homosexueller Paare in Deutschland | -0.000765647058823529 | stern.de |
| 43 | Zustimmung wahrscheinlich: Bundestag debattiert über Ehe für alle | -0.00308503562945368 | stern.de |
| 44 | Netz-Wut gegen Glyphosat-Minister - CSU-Mann Christian Schmidt unter Beschuss | -0.00264306220095694 | Bild.de |
| 45 | Glyphosat: "Entgleiste Diskussion ist erschreckend" | -0.00422409638554217 | ZEIT ONLINE |
| 46 | Ehe für alle: Merkel nennt Streit über Homo-Ehe traurig und unnötig | -0.00337736572890026 | SPIEGEL ONLINE |
| 47 | Toxisch für die Kanzlerin - CSU-Minister verspritzt Gift über GroKo | -0.00488451443569554 | Bild.de |
| 48 | Merkel rückt rückt von klarem CDU-"Nein" zur Ehe für alle ab - FOCUS Online | 0.00085595567867036 | FOCUS ONLINE |
| 49 | "Ehe für alle": Merkel reagiert genial, aber sie gestaltet nicht | 0.000931470588235295 | stern.de |
| 50 | "Ehe für alle": Merkel reagiert genial, aber sie gestaltet nicht | 0.000931470588235295 | stern.de |
| 51 | Historische Abstimmung: "Ehe für alle": Merkel stimmt mit Nein | 9.1566265060241e-05 | stern.de |
| 52 | Ehe für alle - SPD will Nein-Sager der Union mit namentlicher Abstimmung bloßstellen | 0.000203030303030303 | FOCUS ONLINE |
| 53 | Historische Abstimmung: "Ehe für alle": Merkel stimmt mit Nein | 8e-05 | stern.de |
| 54 | Unions-Kompromiss: Der Streit ist noch nicht zu Ende | -0.00241185410334346 | Tagesschau.de |
| 55 | Ehe für alle: Merkel nennt Streit traurig und unnötig | -0.013384858044164 | ZEIT ONLINE |
| 56 | "Brigitte"-Gespräch: Ehe für alle: Merkel rückt vom klaren Nein der CDU ab | -0.000197444089456869 | stern.de |
| 57 | Ehe für alle: Parlamentarier fordern Abstimmung zu gleichgeschlechtlicher Ehe | ZEIT ONLINE | 0.00133064516129032 | ZEIT ONLINE |
| 58 | Seehofer zum Unions-Kompromiss: "Das geschriebene Wort gilt" - WELT | -0.00205822368421053 | DIE WELT |
| 59 | Merkels Äußerungen zur Ehe für alle: Wenige Sätze, große Wirkung | tagesschau.de | -0.000243564356435643 | Tagesschau.de |
| 60 | Barbara Hendricks will ihrer Partnerin einen Heiratsantrag machen | 3.44370860927152e-05 | SPIEGEL ONLINE |
| 61 | Gleichstellung: Union gibt Abstimmung über «Ehe für alle» im Bundestag frei | -0.00312027027027027 | stern.de |
| 62 | "Ehe für alle": "Durchaus geschickt von Merkel" | 0.000108108108108108 | Tagesschau.de |
| 63 | Hendricks will Glyphosat-Einsatz beschränken | -0.00561360544217687 | Tagesschau.de |
| 64 | CDU-Jugend: JU Düsseldorf fordert "sofortigen Rücktritt" Merkels - WELT | -0.0010641638225256 | DIE WELT |
| 65 | Ehe für alle: Bundestag stimmt am Freitag ab - FOCUS Online | 0.00172857142857143 | FOCUS ONLINE |
| 66 | Migrationspolitik: CSU erbost über Jean-Claude Junckers Lob zum Asylkompromiss - WELT | 0.0017275 | DIE WELT |
| 67 | Abstimmung im Bundestag: Wie Angela Merkel ihr "Nein" zur "Ehe für alle" begründet | 0.00212716981132075 | stern.de |
| 68 | Gleichstellung: Ehe für alle: Bald Abstimmung im Bundestag? | -0.000709469696969697 | stern.de |
| 69 | Abstimmung: «Ehe für alle» im Bundestag: Historischer Beschluss möglich | -0.00115984848484848 | stern.de |
| 70 | Nach "Brigitte Live"-Talk: CDU-Rüge für Kanzlerin wegen "Ehe für alle": "Wir haben die Nase voll" | -0.00593166023166023 | stern.de |
| 71 | Minister Schmidt zu Glyphosat-Zulassung: "Habe die Entscheidung für mich getroffen" - SPIEGEL ONLINE - Politik | -0.00302886178861789 | SPIEGEL ONLINE |
| 72 | Christian Schmidt: Agrarminister wird in sozialen Medien bedroht | -0.00148468085106383 | ZEIT ONLINE |
| 73 | Wahlkampfauftritt auf Rügen: Merkel: SPD soll sich von Rot-Rot-Grün abwenden | 0.00184774774774775 | stern.de |
| 74 | Im Schengen-Raum: Merkel: Können auf Grenzkontrollen nicht verzichten | -0.00170542986425339 | stern.de |
| 75 | Morddrohungen gegen Glyphosat-Minister Christian Schmidt (CSU) | -0.00538597285067873 | Bild.de |
| 76 | Vor Abstimmung im Bundestag: CSU bekräftigt Ablehnung der Ehe für alle | -0.00182757009345794 | SPIEGEL ONLINE |
| 77 | Sicherheitspolitik: Merkel für Verlängerung von Grenzkontrollen | -0.001256038647343 | stern.de |
| 78 | Streit um Glyphosat-Votum: Kanzleramt erinnerte an Abmachung - Minister Schmidt ignorierte sie - SPIEGEL ONLINE - Politik | -0.0010015306122449 | SPIEGEL ONLINE |
| 79 | Weitere Debatte: Ehe für alle: Vorentscheidung im Bundestag? | -0.00215987261146497 | stern.de |
| 80 | Fraktionszwang aufgehoben: Merkel gibt Abstimmung über Ehe für alle in Unionsfraktion frei - FOCUS Online | 0.000134228187919463 | FOCUS ONLINE |
| 81 | Abstimmung über "Ehe für alle" schafft es auf die Tagesordnung - FOCUS Online | -0.00433241379310345 | FOCUS ONLINE |
| 82 | Einigung der Union: Seehofers Preis für die Versöhnung in der Flüchtlingsfrage ist hoch - WELT | 0.0078351724137931 | DIE WELT |
| 83 | Glyphosat-Entscheidung: Merkel rügt Alleingang von CSU-Agrarminister | 4.67153284671533e-05 | ZEIT ONLINE |
| 84 | "Brigitte"-Gespräch: Ehe für alle: Merkel rückt vom klaren Nein der CDU ab | 2.35294117647059e-05 | stern.de |
require(ggiraph)
require(ggiraphExtra)sentDF.values %>%
group_by(site, topic_name) %>%
summarise(sentiment = mean(sentiment, na.rm=T)) %>%
spread(key=topic_name, value=sentiment) -> radar
radar %>%
ggRadar(aes(color=site),
rescale = F,
alpha = 0, legend.position = "right") +
labs(title = "")for (i in stmOut$settings$covariates$yvarlevels) {
p <-radar %>%
filter(site == i) %>%
ggRadar(rescale = F,
alpha = 0, legend.position = "right") +
labs(title = i)
ggsave(p, filename = paste0("../figs/radarchart_",i,k,".png"),
device = "png", dpi = 600)
}## Saving 7 x 5 in image
## Saving 7 x 5 in image
## Saving 7 x 5 in image
## Saving 7 x 5 in image
## Saving 7 x 5 in image
## Saving 7 x 5 in image
## Saving 7 x 5 in image
Define Functions
Prepare Dataframes
Plot